#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>

#define WIDTH 40
#define HEIGHT 20
#define SNAKE_MAX_LEN 100
#define SAVE_FILE "save.txt"

typedef struct
{
    int x, y;
} Point;

typedef struct
{
    Point body[SNAKE_MAX_LEN];
    int length;
    int dir; // 0-up, 1-down, 2-left, 3-right
} Snake;

Snake snake;
Point food;
int score = 0;
int highscore = 0;
int sleeptime = 200;
int running = 1;

void gotoxy(int x, int y)
{
    COORD pos = {x * 2, y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void setcolor(int color)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

void printsnake()
{
    setcolor(14);
    printf("\n\n");
    printf("        *****\n");
    printf("       *     *\n");
    printf("      *  0 0  *\n");
    printf("      *   ^   *\n");
    printf("       * --- *\n");
    printf("        *****\n");
    setcolor(7);
}

void welcometogame()
{
    system("cls");
    printsnake();
    printf("\n\n");
    printf("    1. 开始游戏\n");
    printf("    2. 游戏说明\n");
    printf("    3. 显示最高分\n");
    printf("    4. 退出游戏\n");
    printf("\n请选择菜单项(1-4): ");
}

void createMap()
{
    int i, j;
    setcolor(11);
    for (i = 0; i <= HEIGHT; i++)
    {
        for (j = 0; j <= WIDTH; j++)
        {
            if (i == 0 || i == HEIGHT || j == 0 || j == WIDTH)
                printf("■");
            else
                printf("　"); // 注意：这里是全角空格（输入法切换到中文，输入两个空格）
        }
        printf("\n");
    }
    setcolor(7);
}

void File_out()
{
    FILE *fp = fopen(SAVE_FILE, "r");
    if (fp)
    {
        fscanf(fp, "%d", &highscore);
        fclose(fp);
    }
    else
    {
        highscore = 0;
    }
}

void File_in()
{
    FILE *fp = fopen(SAVE_FILE, "w");
    if (fp)
    {
        fprintf(fp, "%d", highscore);
        fclose(fp);
    }
}

void scoreandtips()
{
    gotoxy(WIDTH + 2, 2);
    printf("当前得分: %d", score);
    gotoxy(WIDTH + 2, 4);
    printf("最高得分: %d", highscore);
    gotoxy(WIDTH + 2, 6);
    printf("F1: 加速  F2: 减速");
    gotoxy(WIDTH + 2, 8);
    printf("ESC: 退出");
}

void initsnake()
{
    int i;
    snake.length = 5;
    snake.dir = 3; // 初始方向向右
    for (i = 0; i < snake.length; i++)
    {
        snake.body[i].x = 24 - i; // 修正初始位置
        snake.body[i].y = 5;
    }
}

void drawsnake()
{
    int i;
    setcolor(14);
    for (i = 0; i < snake.length; i++)
    {
        gotoxy(snake.body[i].x, snake.body[i].y);
        printf("●"); // 全部用圆圈
    }
    setcolor(7);
}

int isOnSnake(int x, int y)
{
    int i;
    for (i = 0; i < snake.length; i++)
    {
        if (snake.body[i].x == x && snake.body[i].y == y)
            return 1;
    }
    return 0;
}

void createfood()
{
    int x, y;
    int attempts = 0;
    srand((unsigned)time(NULL));
    do
    {
        x = rand() % (WIDTH - 1) + 1;
        y = rand() % (HEIGHT - 1) + 1;
        attempts++;
        if (attempts > 1000)
        { // 防止死循环
            x = 1;
            y = 1;
            break;
        }
    } while (isOnSnake(x, y));
    food.x = x;
    food.y = y;
    setcolor(12);
    gotoxy(food.x, food.y);
    printf("◆");
    setcolor(7);
}

int biteself()
{
    int i;
    for (i = 1; i < snake.length; i++)
    {
        if (snake.body[0].x == snake.body[i].x &&
            snake.body[0].y == snake.body[i].y)
            return 1;
    }
    return 0;
}

int cantcrosswall()
{
    return (snake.body[0].x == 0 || snake.body[0].x == WIDTH ||
            snake.body[0].y == 0 || snake.body[0].y == HEIGHT);
}

void speedup()
{
    if (sleeptime > 50)
        sleeptime -= 10;
}

void speeddown()
{
    if (sleeptime < 350)
        sleeptime += 30;
}

void snakemove()
{
    int i;
    for (i = snake.length - 1; i > 0; i--)
        snake.body[i] = snake.body[i - 1];

    switch (snake.dir)
    {
    case 0:
        snake.body[0].y--;
        break;
    case 1:
        snake.body[0].y++;
        break;
    case 2:
        snake.body[0].x--;
        break;
    case 3:
        snake.body[0].x++;
        break;
    }
}

void keyboardControl()
{
    if (_kbhit())
    {
        int key = _getch();
        if (key == 224)
        {
            key = _getch();
            switch (key)
            {
            case 72:
                if (snake.dir != 1)
                    snake.dir = 0;
                break; // 上
            case 80:
                if (snake.dir != 0)
                    snake.dir = 1;
                break; // 下
            case 75:
                if (snake.dir != 3)
                    snake.dir = 2;
                break; // 左
            case 77:
                if (snake.dir != 2)
                    snake.dir = 3;
                break; // 右
            }
        }
        else if (key == 27)
        { // ESC
            running = 0;
        }
        else if (key == 0 || key == 224)
        {
            key = _getch();
            if (key == 59)
                speedup(); // F1
            if (key == 60)
                speeddown(); // F2
        }
    }
}

void explation()
{
    system("cls");
    printf("贪吃蛇游戏说明：\n");
    printf("1. 通过方向键控制蛇的移动\n");
    printf("2. 吃到食物长度增加并得分（加速时+2分，减速时+1分）\n");
    printf("3. 撞墙或自咬游戏结束\n");
    printf("4. F1加速/F2减速，ESC退出游戏\n");
    printf("按任意键返回主菜单...\n");
    _getch();
}

void gameover()
{
    system("cls");
    if (score > highscore)
    {
        highscore = score;
        File_in();
        printf("创纪录啦！最高分：%d\n", highscore);
    }
    else
    {
        printf("游戏结束！得分：%d (最高分：%d)\n", score, highscore);
    }
    printf("1. 重玩\n2. 退出游戏\n请选择(1/2): ");
    int ch;
    while (1)
    {
        ch = _getch();
        if (ch == '1')
        {
            score = 0;
            sleeptime = 200;
            running = 1;
            return;
        }
        else if (ch == '2')
        {
            exit(0);
        }
    }
}

void showHighScore()
{
    system("cls");
    printf("最高分记录：%d\n", highscore);
    printf("按任意键返回主菜单...\n");
    _getch();
}

void clearSnake()
{
    int i;
    for (i = 0; i < snake.length; i++)
    {
        gotoxy(snake.body[i].x, snake.body[i].y);
        printf("  ");
    }
}

void clearFood()
{
    gotoxy(food.x, food.y);
    printf("  ");
}

void game()
{
    system("cls");
    createMap();
    scoreandtips();
    initsnake();
    drawsnake();
    createfood();

    while (running)
    {
        clearSnake();
        snakemove();

        if (cantcrosswall() || biteself())
        {
            running = 0;
            break;
        }

        if (snake.body[0].x == food.x && snake.body[0].y == food.y)
        {
            snake.length++;
            score += (sleeptime <= 200) ? 2 : 1;
            clearFood();
            createfood();
            speedup();
        }

        drawsnake();
        scoreandtips();
        Sleep(sleeptime);
        keyboardControl();
    }
    gameover();
}

int main()
{
    File_out();
    int choice;
    while (1)
    {
        welcometogame();
        choice = _getch();
        switch (choice)
        {
        case '1':
            game();
            break;
        case '2':
            explation();
            break;
        case '3':
            showHighScore();
            break;
        case '4':
            exit(0);
        default:
            gotoxy(0, HEIGHT + 5);
            printf("无效输入，请重新选择！");
            Sleep(1000);
        }
    }
    return 0;
}
//